from PyQt4.QtGui import * 
from PyQt4.QtCore import * 
import simplejson as json

class SpriteFrame(QObject):
    attrs = ["index", "width", "height", "number_of_layers"]
    def __init__(self, index, sprite, layers = None, create_empty = True):
        QObject.__init__(self)
        self.index = index
        self.image_names = []
        self.layers = []
        self.sprite = sprite
        self.width = sprite.width
        self.height = sprite.height
        self.loadlayers(layers, create_empty)

    def color_swap(self, layer_index, color_a, color_b):
        image = self.layers[layer_index].toImage()
        result = False
        for y in range(image.height()):
            for x in range(image.width()):
                rgb = QColor(image.pixel(x, y))
                if rgb == color_a:
                    image.setPixel(x, y, color_b.rgb())
                    result = True

        self.layers[layer_index] = QPixmap.fromImage(image)
        return result

    def clone(self):
        n = SpriteFrame(self.index, self.sprite, None, False)
        for layer in self.layers:
            n.add_pixmap_layer(layer)
        
        return n

    def set_selected(self, selected):
        self.selected = selected
        self.emit(SIGNAL("selected(bool)"), selected)
        
    def refresh_image_names(self):
        self.image_names = []
        for layer in self.layers:
            layer_index = self.layers.index(layer)
            self.image_names.append(("images/image_" + str(index) + "_" + str(layer_index) + ".png", (index, layer_index)))

    def add_empty_layer(self):
        tmp = QPixmap(self.width, self.height)
        tmp.fill(QColor(0,0,0,0))
        p = QPainter(tmp)
        self.layers.append(tmp)  
        return self.layers.index(tmp)
        
    def add_image_layer(self, image):
        """ import an image into a new layer """
        tmp = QPixmap.fromImage(image)
        self.layers.append(tmp)  
        self.emit(SIGNAL("layerChange()"))
        return self.layers.index(tmp)
    
    def add_pixmap_layer(self, pixmap):
        """ import an image into a new layer """
        tmp = QPixmap(self.width, self.height)
        tmp.fill(QColor(0,0,0,0))
        p = QPainter(tmp)
        p.drawPixmap(tmp.rect(), pixmap)
        self.layers.append(tmp)  
        self.emit(SIGNAL("layerChange()"))
        return self.layers.index(tmp)
     
    def delete_layer(self, index):
        self.layers.remove(index)
        self.emit(SIGNAL("layerChange()"))
        
    def todict(self):
        #self.refresh_image_names()
        dict = {}
        self.number_of_layers = len(self.layers)
        for attr in SpriteFrame.attrs:
            dict[attr] = getattr(self, attr, None)
        return dict

    def fromdict(dict, index, sprite):
        sf = SpriteFrame(index, sprite)
        for attr in SpriteFrame.attrs:
            setattr(sf, attr, dict[attr])
        return sf
                
    fromdict = staticmethod(fromdict)
    
    def loadlayers(self, images = None, create_empty = True):
        self.layers = []
        
        if images:
	        for i in range(self.number_of_layers):
	            image_name = "images/image_%d_%d.png" % (self.index, i)
	            if image_name in images:
	                image_layer = image_name.split("_")[2].rstrip(".png")
	                #print "frame", self.index, "found", image_name, "layer", image_layer, images[image_name].width(), "x", images[image_name].height()
	                self.add_image_layer(images[image_name])
        elif create_empty:
            self.add_empty_layer()

        self.number_of_layers = len(self.layers)

    def move_layer_up(self, layer_idx):
        if layer_idx > 0:
            layer = self.layers[layer_idx]
            self.layers.remove(layer)
            self.layers.insert(layer_idx - 1, layer)
            self.emit(SIGNAL("layerChange()"))
            return layer_idx - 1

    def move_layer_down(self, layer_idx):
        if layer_idx < (len(self.layers) - 1):
            layer = self.layers[layer_idx]
            self.layers.remove(layer)
            self.layers.insert(layer_idx + 1, layer)
            self.emit(SIGNAL("layerChange()"))
            return layer_idx + 1

    def merge_layer_down(self, layer_idx):
        if layer_idx > 0:
            layer_a = self.layers[layer_idx - 1]
            layer_b = self.layers[layer_idx]
            p = QPainter(layer_a)
            p.drawPixmap(0,0,layer_b)
            p.end()
            self.layers.remove(layer_b)
            self.emit(SIGNAL("layerChange()"))
            return layer_idx - 1

    def flip(self, horizontally, vertically):
        for index,layer in enumerate(self.layers):
            self.flip_layer(index, horizontally, vertically)

    def flip_layer(self, index, horizontally, vertically):
        im = self.layers[index].toImage()
        im = im.mirrored(horizontally, vertically)
        self.layers[index] = QPixmap.fromImage(im)
        self.emit(SIGNAL("layerChange()"))

    def get_pixmap(self, whiteout = False):
        # TODO: this is producing some unusual results, no transparency
        pixmap = QPixmap(self.sprite.width, self.sprite.height)
        # NOTE: do not use fill if a QPainter is open
        if not whiteout:
            pixmap.fill(QColor(0,0,0,0))
            p = QPainter(pixmap)
            p.end()
        else:
            pixmap.fill(QColor("white"))

        p = QPainter(pixmap)
        for layer_index,layer in enumerate(self.layers):
            p.setOpacity(1.0)
            p.drawPixmap(0,0,layer)
        p.end()
        return pixmap

    def nudge(self, layer_index, offset):
        layer = self.layers[layer_index]

        tmp = QPixmap(layer.size())

        tmp.fill(QColor(0,0,0,0))

        p = QPainter(tmp)

        p.drawPixmap(offset, layer)

        p.end()

        layer.fill(QColor(0,0,0,0))

        p = QPainter(layer)

        p.drawPixmap(0, 0, tmp)

        p.end()

class Sprite(QObject):
    attrs = ["width", "height", "palette", "number_of_frames", "frames"]
    def __init__(self, width, height):
        QObject.__init__(self)
        self.number_of_frames = 0
        self.palette = []
        self.frames = []
        self.width = width
        self.height = height

        # Used to optimize drawing in sprite editor.
        self.dirty = True

        # Used for move_frame, True if frames have changed. 
        self.frame_dirty = False


    def clone(self):
        s = Sprite(self.width, self.height)
        for frame in self.frames:
            s.frames.append(frame.clone())
        return s
            
    def add_empty_frame(self):
        frame = SpriteFrame(len(self.frames), self)
        self.frames.append(frame)
        self.emit(SIGNAL("frameAdded(QObject)"), frame)
        if(len(self.frames[0].layers) > 1):
            for i in range(len(self.frames[0].layers) - 1):
                frame.add_empty_layer()
        return self.frames.index(frame)
    
    def duplicate_frame(self, index):
        frame = self.frames[index].clone()
        self.frames.append(frame)
        frame.index = self.frames.index(frame)
        self.emit(SIGNAL("frameAdded(QObject)"), frame)
        return self.frames.index(frame)
    
    def delete_frame(self, index):
        if index < len(self.frames):
	        frame = self.frames[index]
	        self.frames.remove(self.frames[index])
	        self.emit(SIGNAL("frameRemoved(QObject)"), frame)
    
    def move_frame(self, index, index_to):
        if index < len(self.frames) and index != index_to:
            frame = self.frames[index]
            self.frames.remove(frame)
            self.frames.insert(index_to, frame)
            self.frame_dirty = True

    def reset_dirty_flag(self):
        self.dirty = False

    def clear_frames(self):
        self.frames = []
        
    def flip(self, horizontally, vertically):
        for index,frame in enumerate(self.frames):
            frame.flip(horizontally, vertically)

    def copy_layer_to_all_frames(self, source_frame, layer_index):
        # TODO: Encapsulate in command.

        layer = source_frame.layers[layer_index]
   
        for frame in self.frames:
            if frame != source_frame:
                dest_layer = frame.layers[layer_index]
                dest_layer.fill(QColor(0,0,0,0))
                p = QPainter(dest_layer)
                p.drawPixmap(0,0,layer)
                p.end()

        self.emit(SIGNAL("frameAdded(QObject)"), source_frame)


    """Loading / Saving"""

    def todict(self):
        dict = {}
        for attr in self.attrs:
            if attr != "frames":
	            dict[attr] = getattr(self, attr, None)
            else:
		        dict["frames"] = []
		        for frame in self.frames:
		            dict["frames"].append(frame.todict())
            
        return dict

    def fromjson(j, images):
        dict = json.loads(j)

        sprite = Sprite(dict["width"], dict["height"])

        for attr in Sprite.attrs:
            if attr != "frames":
                setattr(sprite, attr, dict[attr])
            else:
                for frame in dict["frames"]:
                    frame_index = dict["frames"].index(frame)
                    f = SpriteFrame.fromdict(frame, frame_index, sprite)
                    sprite.frames.append(f)
                    f_index = sprite.frames.index(f)
                    sprite.frames[f_index].loadlayers(images)

        #print "Loaded sprite with %d frames..." % (len(dict["frames"]))

        return sprite
                    
    fromjson = staticmethod(fromjson)
    
